import KMeans from "./KMeans";
/**
 * 数据分段
 */
export default {
  SEGMENTTYPE: {
    KMEANS: "KMEANS", //  聚类分段
    ISOMETRIC: "ISOMETRIC", // 等距分段
    SQUARE: "SQUARE", //  平方根分段
    STANDARD: "STANDARD", //  标准差分段
    LOGARITHM: "LOGARITHM" //  对数分段
  },
  /**
   * 根据类型进行数据分段,所有的都迁移过来了，暂时只使用到了KMEANS
   * @param {Array} datas  数值数组,此处数据是排好序的了 (从小到大)
   * @param {Number} num 分段数目
   * @param {String} type 分段类型
   */
  segmentUtil(data, segment, type) {
    // 此处最大最小值都是排序过得，
    let max = Math.max.apply(Math, data);
    let min = Math.min.apply(Math, data);
    // 如果数据不足分段数的话，补全数据
    if (data.length < segment) {
      let dataLen = data.length;
      let temp = [];
      for (let i = 0; i < segment - dataLen + 1; i++) {
        temp.push(0);
      }
      temp = temp.concat(data);
      data = temp;
    }
    // 数据分段
    if (type === this.SEGMENTTYPE.KMEANS) {
      let km = new KMeans(data, segment);
      let re = km.result;
      let len = re.length;
      for (let i = 0; i < len; i++) {
        if (typeof re[i] == "undefined") {
          re[i] = 0;
        }
      }
      // 升序排序
      re.sort(function (a, b) {
        return a - b;
      });
      // 最大最小值处理
      re[0] = re[0] > min ? min : re[0];
      re[len - 1] = re[len - 1] < max ? max : re[len - 1];
      return re;
    } else if (type === this.SEGMENTTYPE.ISOMETRIC) {
      //  等距分段(其实数据已经是经过从小到大排序的了)
      let maxVal = data[data.length - 1],
        minVal = data[0],
        per = (maxVal - minVal) / segment;
      let dataRamp = [];
      for (let i = 0; i < segment; i++) {
        dataRamp.push(minVal + i * per);
      }
      dataRamp.push(maxVal);
      return dataRamp;
    } else if (type === this.SEGMENTTYPE.SQUARE) {
      /**
        平方根分段(对专题变量所确定的专题值的平方根为分段数据进行等距离分段。首先取所有专题值的平方根，
        然后进行等距离分段，得到处理后数据的分段点，然后将这些分段点的值进行平方得到对应专题值的分段点，
        从而得到专题值的分段方案。)
      */
      let dataRamp = [];
      for (let i = 0, len = data.length; i < len; i++) {
        data[i] = Math.sqrt(data[i]);
      }
      let maxVal = Math.sqrt(data[data.length - 1]),
        minVal = Math.sqrt(data[0]),
        per = (maxVal - minVal) / segment;
      for (let i = 0; i < segment; i++) {
        dataRamp.push(Math.pow(minVal + i * per, 2));
      }
      dataRamp.push(Math.pow(maxVal, 2));
      return dataRamp;
    } else if (type === this.SEGMENTTYPE.STANDARD) {
      /**
        标准差分段(反映各对象的某属性值对其平均值的偏离。首先计算出专题变量所确定的专题值的平均值和标准
        偏差，在此基础上进行分段。标准差分段的每个分段长度都是一个标准差，最中间的那一段以平均值为中心，
        左边分段点和右边分段点分别与平均值相差0.5个标准差。标准差分段方法所得的“段数”由计算结果决定，
        用户不可控制。)
        */
      let stdev, average, max_mun, min_mun, sum_seg;
      // 计算出最大最小值
      (max_mun = data[data.length - 1]), (min_mun = data[0]);
      // 计算标准差
      let temp = 0,
        sum = 0;
      for (let i = 0, len = data.length; i < len; i++) {
        sum += data[i];
      }
      average = sum / data.length;
      for (let i = 0, len = data.length; i < len; i++) {
        temp += Math.pow(data[i] - average, 2);
      }
      stdev = Math.sqrt(temp / data.length);
      // 计算出平均值所在左右分段点值和分段数
      let seg_r = average + stdev / 2,
        num_r = 0;
      while (seg_r < max_mun) {
        seg_r += stdev;
        num_r++;
      }
      let seg_l = average - stdev / 2,
        num_l = 0;
      while (seg_l > min_mun) {
        seg_l -= stdev;
        num_l++;
      }
      // 计算总的分段数
      sum_seg = num_l + num_r + 1;
      // 计算每一段的值
      let dataRamp = [];
      for (let i = 0; i < sum_seg + 1; i++) {
        dataRamp.push(seg_l + i * stdev);
      }
      return dataRamp;
    } else if (type === this.SEGMENTTYPE.LOGARITHM) {
      /**
        对数分段（与平方根分段方法基本相同，所不同的是平方根方法是对专题值取平方根，而对数分段方法是对
        专题值取对数，即对专题值的以10为底的对数值进行等距离分段。首先对所有专题值的对数进行等距离分段，
        得到处理后数据的分段点，然后以10为底，这些分段点的值作为指数的幂，得到对应的专题值的各分段点的
        值，从而得到分段方案。）
        */
      let dataRamp = [],
        maxVal,
        minVal,
        per;
      for (let i = 0, len = data.length; i < len; i++) {
        data[i] = Math.log(data[i]);
      }
      (maxVal = data[data.length - 1]),
      (minVal = data[0]),
      (per = (maxVal - minVal) / segment);
      for (let i = 0; i < segment; i++) {
        dataRamp.push(Math.pow(10, minVal + i * per));
      }
      dataRamp.push(Math.pow(10, maxVal));
      return dataRamp;
    }
  }
};
